package com.echat.serviceapigateway.security.aop;

import com.echat.commonlib.constant.ErrorCode;
import com.echat.commonlib.constant.ErrorCodeMsg;
import com.echat.commonlib.exception.exc.EchatSecurityException;
import com.echat.commonlib.exception.exc.ValidateFailedException;
import com.echat.commonlib.util.StringUtil;
import com.echat.serviceapigateway.security.cache.RedisTokenCacher;
import com.echat.serviceapigateway.security.model.authentication.User;
import com.echat.serviceapigateway.security.model.authorization.TokenGetLimit;
import com.echat.serviceapigateway.security.service.TokenGetLimiService;
import com.echat.serviceapigateway.security.service.UserService;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;

/**
 * Created by chenmohan on 2018/09/05
 *
 * @description 对AuthenticateController获取Token业务逻辑进行增强，使用Redis对用户每天获取token的次数作了限制
 */
@Aspect
@Component
@Log4j2
@ConditionalOnExpression("${echat.service.tokenGetLimit.enalbe:false}")
public class TokenGetLimitAspect {

    @Autowired
    UserService userService;

    @Autowired
    RedisTokenCacher redisTokenCacher;

    @Autowired
    TokenGetLimiService tokenGetLimiService;

    @Pointcut("execution(* com.echat.serviceapigateway.security.controller.AuthenticateController.*Token(..))")
    public void getTokenPoint(){}

    @Around("getTokenPoint()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        String accessKey = (String) pjp.getArgs()[0];
        if(StringUtil.isEmpty(accessKey)){
            throw new ValidateFailedException("field[accessKey] must not be null or empty");
        }

        User user = userService.getUserByAccessKey(accessKey);
        if(user==null){
            throw new EchatSecurityException(ErrorCode.INVAILD_ACCESS_KEY, ErrorCodeMsg.INVAILD_ACCESS_KEY);
        }
        Long userId = user.getId();
        Integer times = tokenGetLimiService.getTokenGetLimitByUserId(userId);
        if ( times == null || times <= 0 ){  //判断token请求次数是否小于等于0
            throw new EchatSecurityException(ErrorCode.EXCEEDED_GET_TOKEN_LIMIT, ErrorCodeMsg.EXCEEDED_GET_TOKEN_LIMIT);
        }

        //处理token业务逻辑
        Object accessToken = pjp.proceed();

        //处理完毕后，将token可请求次数-1
        TokenGetLimit update = TokenGetLimit.builder()
                                            .userId(userId)
                                            .getTimes(times-1).build();
        tokenGetLimiService.modifyTokenGetLimit(update);

        return accessToken;
    }

}
